package cn.buk.tms.eotms.service;

import cn.buk.common.flight.dto.FlightBasicInfo;
import cn.buk.common.util.DateUtil;
import cn.buk.tms.common.dto.flight.BaseChangeOrderFlightDto;
import cn.buk.tms.eotms.dao.CustomerDao;
import cn.buk.tms.eotms.dao.ReportDao;
import cn.buk.tms.eotms.dto.RoleInfo;
import cn.buk.tms.eotms.entity.FlightInfo;
import cn.buk.tms.eotms.report.dto.*;
import cn.buk.tms.eotms.util.BillUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ReportServiceImpl extends BaseAbstractService implements ReportService {

  @Autowired
  private ReportDao dao;

  @Autowired
  private CustomerDao customerDao;

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_MANAGER})
  public List<ReportFlightTicketDto> searchFlightMonthlySale(final int userId, final Date beginDate, final Date endDate) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    return doSearchFlightMonthlySale(ownerId, customerId, beginDate, endDate);
  }

  @Override
  public List<ReportFlightRefundDto> searchFlightRefundMonthly(final int userId, Date beginDate, Date endDate) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    return doSearchFlightRefundMonthly(ownerId, customerId, beginDate, endDate);
  }

  @Override
  public List<ReportFlightChangeDto> searchFlightChangeMonthly(int userId, Date beginDate, Date endDate) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    return doSearchFlightChangeMonthly(ownerId, customerId, beginDate, endDate);
  }

  @Override
  public List<ReportVasDto> searchVasMonthly(int userId, Date beginDate, Date endDate) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    return doSearchVasMonthly(ownerId, customerId, beginDate, endDate);
  }

  @Override
  public List<ReportHotelDto> searchHotelMonthly(int userId, Date beginDate, Date endDate) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    return dao.searchHotelOrders(ownerId, customerId, beginDate, endDate);
  }

  @Override
  public List<ReportTrainDto> searchTrainMonthly(int userId, Date beginDate, Date endDate) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    return dao.searchTrainOrders(ownerId, customerId, beginDate, endDate);
  }

  @Override
  public List<ReportStatDailyDto> statDailySale(int userId, LocalDate beginDate, LocalDate endDate) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    return dao.statDaily(ownerId, customerId, beginDate, endDate);
  }

  @Override
  public List<ReportStatisticDto> statMonthSaleByAirlines(int userId, Date beginDate, Date endDate) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    List<ReportStatisticDto> list0 = dao.statMonthSaleByAirlines(ownerId, customerId, beginDate, endDate);

    Map<String, ReportStatisticDto> map = new HashMap<>();
    for(ReportStatisticDto dto: list0) {
      final String carrier = dto.getCarrier();
      if (map.containsKey(carrier)) {
        ReportStatisticDto dto1 = map.get(carrier);
        dto1.setCount(dto1.getCount() + dto.getCount());
        dto1.setTotalAmount(dto1.getTotalAmount() + dto.getTotalAmount());
        dto1.setTotalCost(dto1.getTotalCost() + dto.getTotalCost());
        dto1.setTotalProfit(dto1.getTotalProfit() + dto.getTotalProfit());
      } else {
        map.put(carrier, dto);
      }
    }

    List<ReportStatisticDto> list1 = new ArrayList<>(map.values());
    list1 = list1.stream().sorted(Comparator.comparing(ReportStatisticDto::getCount).reversed()).collect(Collectors.toList());

    return list1;
  }

  @Override
  @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_MANAGER})
  public MonthlyReport searchMonthlyReport(final int userId, final Date beginDate, final Date endDate) {
    MonthlyReport report = new MonthlyReport();

    report.setFlights(this.searchFlightMonthlySale(userId, beginDate, endDate));
    report.setRefunds(this.searchFlightRefundMonthly(userId, beginDate, endDate));
    report.setChanges(this.searchFlightChangeMonthly(userId, beginDate, endDate));
    report.setServices(this.searchVasMonthly(userId, beginDate, endDate));
    report.setHotels(this.searchHotelMonthly(userId, beginDate, endDate));
    report.setTrains(this.searchTrainMonthly(userId, beginDate, endDate));

    //如果是经理角色，则只能查看本部门以及下级部门的
    Set<String> roles = getRolesByUserId(userId);
    if (!roles.contains(RoleInfo.ROLE_ADMIN)) {
      //不是管理员，是经理角色，只能查看本部门的
      int deptId = getCustomerDeptIdByUserId(userId);
      List<String> usernames = customerDao.getCustomerDepartmentOperator(getOwnerIdByUserId(userId), getCustomerIdByUserId(userId), deptId);

      report.setFlights(report.getFlights().stream().filter(t -> usernames.contains(t.getOperator())).collect(Collectors.toList()));
      report.setRefunds(report.getRefunds().stream().filter(t -> usernames.contains(t.getOperator())).collect(Collectors.toList()));
      report.setChanges(report.getChanges().stream().filter(t -> usernames.contains(t.getOperator())).collect(Collectors.toList()));
      report.setServices(report.getServices().stream().filter(t -> usernames.contains(t.getOperator())).collect(Collectors.toList()));
      report.setHotels(report.getHotels().stream().filter(t -> usernames.contains(t.getOperator())).collect(Collectors.toList()));
      report.setTrains(report.getTrains().stream().filter(t -> usernames.contains(t.getOperator())).collect(Collectors.toList()));

    }

    report.calc();

    return report;
  }

  private List<ReportVasDto> doSearchVasMonthly(int ownerId, int customerId, Date beginDate, Date endDate) {
    return dao.searchVasOrders(ownerId, customerId, beginDate, endDate);
  }

  private List<ReportFlightChangeDto> doSearchFlightChangeMonthly(int ownerId, int customerId, Date beginDate, Date endDate) {
    final long start = System.currentTimeMillis();

    List<ReportFlightChangeDto> tickets = dao.searchFlightChanges(ownerId, customerId, beginDate, endDate);
    final long end1 = System.currentTimeMillis() - start;

    List<ReportFlightChangeDto> results = new ArrayList<>();
    for(ReportFlightChangeDto ticket: tickets) {
      List<FlightInfo> flights = new ArrayList<>();
      BillUtil.processRouteDetail(ticket.getRouteDetail(), flights);

      for(FlightInfo flt: flights) {
        BaseChangeOrderFlightDto dto = new BaseChangeOrderFlightDto();
        BeanUtils.copyProperties(flt, dto);

        dto.setFltType(flt.getFlightType());
        try {
          dto.setDdate(DateUtil.convertToDate(flt.getDdate(), "yyyy-MM-dd"));
        } catch (ParseException ignored) {
        }

        dto.setDportName(getAirportName(dto.getDport()));
        dto.setAportName(getAirportName(dto.getAport()));

        ticket.getFlights().add(dto);
      }

        results.add(ticket);
    }
    final long end2 = System.currentTimeMillis() - start;
//    logger.info("doSearchFlightChangeMonthly: " + end1 + " ms, " + end2 + " ms.");

    return results;
  }

  private List<ReportFlightRefundDto> doSearchFlightRefundMonthly(final int ownerId, final int customerId,
                                                                  final Date beginDate,
                                                                  final Date endDate) {
    List<ReportFlightRefundDto> tickets = dao.searchFlightRefunds(ownerId, customerId, beginDate, endDate);

    List<ReportFlightRefundDto> results = new ArrayList<>();
    for(ReportFlightRefundDto ticket: tickets) {
      List<FlightInfo> flights = new ArrayList<>();
      BillUtil.processRouteDetail(ticket.getRouteDetail(), flights);

      for(FlightInfo flt: flights) {
        FlightBasicInfo dto = new FlightBasicInfo();
        BeanUtils.copyProperties(flt, dto);

        try {
          dto.setDdate(DateUtil.convertToDate(flt.getDdate(), "yyyy-MM-dd"));
        } catch (ParseException ignored) {
        }

        dto.setDportName(getAirportName(dto.getDport()));
        dto.setAportName(getAirportName(dto.getAport()));

        ticket.getFlights().add(dto);
      }

      results.add(ticket);
    }

    return results;
  }

  /**
   * 搜索月报
   */
  private List<ReportFlightTicketDto> doSearchFlightMonthlySale(final int ownerId, final int customerId,
                                                                final Date beginDate, final Date endDate) {
    final long start = System.currentTimeMillis();

    List<ReportFlightTicketDto> tickets = dao.searchFlightTickets(ownerId, customerId, beginDate, endDate);
    final long end1 = System.currentTimeMillis() - start;

    List<ReportFlightTicketDto> results = new ArrayList<>();
    for(ReportFlightTicketDto ticket: tickets) {
      List<FlightInfo> flights = new ArrayList<>();
      BillUtil.processRouteDetail(ticket.getRouteDetail(), flights);

      for(FlightInfo flt: flights) {
        FlightBasicInfo dto = new FlightBasicInfo();
        BeanUtils.copyProperties(flt, dto);

        try {
          dto.setDdate(DateUtil.convertToDate(flt.getDdate(), "yyyy-MM-dd"));
        } catch (ParseException ignored) {
        }

        dto.setDportName(getAirportName(dto.getDport()));
        dto.setAportName(getAirportName(dto.getAport()));

        ticket.getFlights().add(dto);
      }

      results.add(ticket);
    }
    final long end2 = System.currentTimeMillis() - start;
//    logger.info("doSearchFlightMonthlySale: " + end1 + " ms, " + end2 + " ms.");

    return results;
  }
}
